package com.googlecode.xapper

import static org.junit.Assert.*
import static org.hamcrest.Matchers.*

import nu.xom.*

import com.googlecode.xapper.HtmlElementWrapper
import org.junit.Test

public class TestElementWrapper{

	def context = new XPathContext("html", "http://www.w3.org/1999/xhtml");
	def static XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml"
	
	private Builder builder = new Builder()

	@Test
	public void shouldCreateAnElement() {
		def wrapper = HtmlElementWrapper.create("p")
		def element = wrapper.asElement()
		assertThat(element.getLocalName(), is(equalTo("p")))
	}
	
	@Test
	public void shouldCreateXhtmlElements() {
		def wrapper = HtmlElementWrapper.create("p")
		def element = wrapper.asElement()
		
		Nodes nodes = element.query("//html:p", context);
		
		assertThat(nodes, is(notNullValue()))
		assertThat(nodes.size(), is(1))
		assertThat(nodes.get(0), is(notNullValue()))
	}
	
	@Test
	public void shouldCreateAttributesOnAnElement() {
		def wrapper = HtmlElementWrapper.create("p")
		
		wrapper.withAttribute("id", "mine")
		
		def element = wrapper.asElement()
		
		assertThat(element.getAttributeValue("id"), is(equalTo("mine")))
	}
	
	@Test
	public void shouldIndicateAnElementHasAnAttribute() {
		
		def document = builder.build(new StringReader('<span id="Guys">Dolls</span>'))
		
		def wrapper = HtmlElementWrapper.element(document)
		
		assertThat(wrapper.hasAttribute("id"), is(true))
	}
	
	@Test
	public void shouldIndicateAnElementDoesNotHaveAnAttribute() {
		def document = builder.build(new StringReader('<img />'))
		
		def wrapper = HtmlElementWrapper.element(document)
		
		assertThat(wrapper.hasAttribute("id"), is(false))
	}
	
	@Test
	public void shouldCreateAChildElementForADiv() {
		Element element = new Element("div", XHTML_NAMESPACE)
		element.addAttribute(new Attribute("id", "top"))
		
		def wrapper = HtmlElementWrapper.element(element)
		
		wrapper.withChild("div")
		
		def nodes = element.query('//html:div[@id=\'top\']/html:div', context)
		
		assertThat(nodes.size(), is(1))
	}
	
	@Test
	public void shouldAddTextToANode(){
		
		def hello = "Hello World"
		
		Element html = new Element("html", XHTML_NAMESPACE);
		
		def wrapper = HtmlElementWrapper.element(html)
		
		wrapper.withChild("head").withChild("title")
			.withText(hello)
			
		def nodes = html.query('//html:html/html:head/html:title', context)
		
		assertThat(nodes.size(), is(1))
		assertThat(nodes.get(0).getLocalName(), is(equalTo("title")))
		assertThat(nodes.get(0).getValue(), is(equalTo(hello)))
	}
	
	@Test
	public void shouldAppendTextToNodes() {
		def hello = "Hello"
		def world = "World"
		
		Element p = HtmlElementWrapper.create("p").asElement();
		
		def wrapper = HtmlElementWrapper.element(p)
		wrapper.withText(hello).withText(" ").withText(world)
		
		assertThat(wrapper.asElement().getValue(), is(equalTo("Hello World")))
	}
	
	@Test
	public void shouldYieldTheParentOfTheWrappedElement() {
		def wrapper = HtmlElementWrapper.create("div")
		wrapper.withAttribute("id", "parent")
			.withChild("p")
			.withAttribute("id", "child");
		
		assertThat(wrapper.parent().asElement().getAttributeValue("id"), is(equalTo("parent")))
	}
	
	@Test
	public void shouldReturnTheElementItselfIfThereIsNoParent() {
		def wrapper = HtmlElementWrapper.create("div")
			.withAttribute("id", "singleton");
		
		assertThat(wrapper.parent().asElement().getAttributeValue("id"), is(equalTo("singleton")))
	}
	
	@Test
	public void shouldReturnTheRootOfTheTree() {
		def wrapper = HtmlElementWrapper.create("div")
			.withAttribute("id", "root")
			.withChild("div")
			.withChild("p")
			.withChild("span")
			.withAttribute("id", "tip")
		
		def root = wrapper.root()
		
		assertThat(root.asElement().getAttributeValue("id"), is(equalTo("root")))
	}
	
	@Test
	public void shouldCreateASiblingNode() {
		def element = HtmlElementWrapper.create("div")
			.withId("root")
			.withChild("div")
			.withAttribute("id", "kida")
			.withSibling("div")
			.withId("kidb")
			.asElement()
		
		assertThat(element.query("/html:div/html:div[2]", context).get(0).getAttributeValue("id"), is(equalTo("kidb")))
	}
	
	@Test
	public void shouldMakeTheSibilingTheWrappedElementWhenCreatingASibiling() {
		def element = HtmlElementWrapper.create("div")
			.withChild("div")
			.withAttribute("id", "take1")
			.withSibling("div")
			.withAttribute("id", "take2")
			.asElement()
			
		assertThat(element.getAttributeValue("id"), is(equalTo("take2")))	
		
	}
	
	@Test
	public void shouldCreateChildrenInTheHtmlNamespace() {
		def element = HtmlElementWrapper.create("div").withChild("div").asElement()
		
		assertThat(element.getNamespaceURI(), is(equalTo(XHTML_NAMESPACE)))
	}
	
	@Test
	public void shouldAddTextToASibling() {
		def element = HtmlElementWrapper.create("div")
			.withChild("p")
			.withSibling("p")
			.withText("My Text")
			.asElement()
		
		assertThat(element.getValue(), is(equalTo("My Text")))
	}
	
	@Test
	public void shouldSayTheParentOfAParentlessElementIsItself() {
		def element = HtmlElementWrapper.create("p")
			.withId("orphan")
			.parent()
			.asElement()
			
		assertThat(element.getAttributeValue("id"), is(equalTo("orphan")))
	}
	
	@Test(expected=IllegalStateException.class)
	public void shouldNotCreateASiblingForARootElement() {
		def element = HtmlElementWrapper.create("p")
			.withSibling("p")
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void shouldNotAllowNegativeHeadingLevels() {
		HtmlElementWrapper.create("body")
			.withHeading(-1, "Noooo!")
	}
}
